﻿using System;
using System.Collections;
using System.Web;

namespace Direct.Context
{
    [System.Diagnostics.DebuggerStepThrough]
    class SessionDataService : ISessionDataService
    {
        private const string CONTEXT_SESSION_SLOT_NAME = "___http_session_data_slot___";

        // Contexto de thread, usado em aplicações multi-thread ou single-thread que não estejam num
        // contexto Http. Nesse caso um dado de Sessão é tratado com um dado de contexto de chamada.
        // OBS: apesar de, no caso de back threads, IContextDataService e ISessionDataService
        // desempenharem o mesmo papel na prática (não existe contexto de chamada em uma back thread),
        // os valores são armazenados em slots diferentes, portanto não se misturam.
        [ThreadStatic]
        private static Hashtable _threadContextItems;

        private Hashtable InternalContext
        {
            get
            {
                if (HttpContext.Current == null || HttpContext.Current.Session == null)
                    return (_threadContextItems = _threadContextItems ?? new Hashtable());
                else
                {
                    var result = (Hashtable)HttpContext.Current.Session[CONTEXT_SESSION_SLOT_NAME];
                    if (result == null)
                        HttpContext.Current.Session[CONTEXT_SESSION_SLOT_NAME] = result = new Hashtable();
                    return result;
                }
            }
        }


        public Object Get(String key)
        {
            return InternalContext[key];
        }

        public void Set(String key, Object value)
        {
            InternalContext[key] = value;
        }

        public bool Exists(String key)
        {
            return InternalContext.ContainsKey(key);
        }

        public int Count { get { return InternalContext.Count; } }

        public void Remove(String key)
        {
            InternalContext.Remove(key);
        }

        public object this[String key]
        {
            get { return Get(key); }
            set { Set(key, value); }
        }

        public void Clear()
        {
            InternalContext.Clear();
        }
    }
}
